RX data is now moved in a domain-memory page, but still copied at the end.
#endif
/* Check if the packet is long enough to accept without copying
to a minimally-sized skbuff. */
- if (pkt_len < tulip_rx_copybreak
- && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
+ //if (pkt_len < tulip_rx_copybreak
+ // && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
+ if (0) {
skb->dev = dev;
skb_reserve(skb, 2); /* 16 byte align the IP header */
pci_dma_sync_single(tp->pdev,
if (direction == PCI_DMA_NONE)
BUG();
flush_write_buffers();
- return virt_to_bus(ptr);
+
+ if ((unsigned long) ptr > PAGE_OFFSET)
+ return virt_to_bus(ptr);
+
+ /* If an address that is not in hypervisor VM is passed to this
+ * function (ie > PAGE_OFFSET) we assume that the passer knows
+ * what they are doing, and have passed a physical address that
+ * should not be converted here. This is a little hackish, but
+ * is being added to allow references to domain memory in order
+ * to support zero-copy network code.
+ */
+
+ return (dma_addr_t) ptr;
}
/* Unmap a single streaming mode DMA translation. The dma_addr and size
#define VIF_DROP -3
#define VIF_ANY_INTERFACE -4
+//skb_type values:
+#define SKB_NORMAL 0
+#define SKB_ZERO_COPY 1
+
#define HAVE_ALLOC_SKB /* For the drivers to know */
#define HAVE_ALIGNABLE_SKB /* Ditto 8) */
#define SLAB_SKB /* Slabified skbuffs */
unsigned int data_len;
unsigned int csum; /* Checksum */
unsigned char __unused, /* Dead field, may be reused */
- cloned, /* head may be cloned (check refcnt to be sure). */
+ cloned, /* head may be cloned (check refcnt to be sure) */
pkt_type, /* Packet class */
ip_summed; /* Driver fed us an IP checksum */
__u32 priority; /* Packet queueing priority */
void (*destructor)(struct sk_buff *); /* Destruct function */
- int src_vif; /* vif we came from */
- int dst_vif; /* vif we are bound for */
+ unsigned int skb_type; /* SKB_NORMAL or SKB_ZERO_COPY */
+ struct pfn_info *pf; /* record of physical pf address for freeing */
+ int src_vif; /* vif we came from */
+ int dst_vif; /* vif we are bound for */
+ struct skb_shared_info shinfo; /* shared info is no longer shared in Xen. */
+
extern void __kfree_skb(struct sk_buff *skb);
extern struct sk_buff * alloc_skb(unsigned int size, int priority);
+extern struct sk_buff * alloc_zc_skb(unsigned int size, int priority);
extern void kfree_skbmem(struct sk_buff *skb);
extern struct sk_buff * skb_clone(struct sk_buff *skb, int priority);
extern struct sk_buff * skb_copy(const struct sk_buff *skb, int priority);
extern void skb_under_panic(struct sk_buff *skb, int len, void *here);
/* Internal */
-#define skb_shinfo(SKB) ((struct skb_shared_info *)((SKB)->end))
+//#define skb_shinfo(SKB) ((struct skb_shared_info *)((SKB)->end))
+#define skb_shinfo(SKB) ((struct skb_shared_info *)(&(SKB)->shinfo))
/**
* skb_queue_empty - check if a queue is empty
{
struct sk_buff *skb;
- skb = alloc_skb(length+16, gfp_mask);
+ //skb = alloc_skb(length+16, gfp_mask);
+ skb = alloc_zc_skb(length+16, gfp_mask);
if (skb)
skb_reserve(skb,16);
return skb;
#include <linux/pkt_sched.h>
#include <linux/event.h>
+#include <asm/domain_page.h>
#define BUG_TRAP ASSERT
#define notifier_call_chain(_a,_b,_c) ((void)0)
if (skb->stamp.tv_sec == 0)
get_fast_time(&skb->stamp);
+ /* Attempt to handle zero-copy packets here: */
+ if (skb->skb_type == SKB_ZERO_COPY)
+ {
+ skb->head = (u8 *)map_domain_mem(((skb->pf - frame_table) << PAGE_SHIFT));
+
+ /* remapping this address really screws up all the skb pointers. We need
+ * to map them all here sufficiently to get the packet demultiplexed.
+ */
+
+ skb->data = skb->head;
+ skb_reserve(skb,16); // need to ensure that all the drivers and not just tulip do this.
+ skb->mac.raw = skb->data;
+ skb->data += ETH_HLEN;
+ }
+
/* The code is rearranged so that the path is the most
short when CPU is congested, but is still operating.
*/
netdev_rx_stat[this_cpu].dropped++;
local_irq_restore(flags);
+ if (skb->skb_type == SKB_ZERO_COPY)
+ unmap_domain_mem(skb->head);
+
kfree_skb(skb);
return NET_RX_DROP;
found:
+ if (skb->skb_type == SKB_ZERO_COPY) {
+ unmap_domain_mem(skb->head);
+ //skb->head = (u8 *)((skb->pf - frame_table) << PAGE_SHIFT);
+ skb->head = skb->data = skb->tail = (void *)0xdeadbeef;
+ }
hyp_event_notify(cpu_mask);
local_irq_restore(flags);
return 0;
rx = shadow_ring->rx_ring+i;
if ( (skb->len + ETH_HLEN) < rx->size )
rx->size = skb->len + ETH_HLEN;
+
+ /* remap the packet again. This is very temporary and will shortly be
+ * replaced with a page swizzle.
+ */
+
+ if (skb->skb_type == SKB_ZERO_COPY)
+ {
+ skb->head = (u8 *)map_domain_mem(((skb->pf - frame_table) << PAGE_SHIFT));
+ skb->data = skb->head;
+ skb_reserve(skb,16);
+ skb->mac.raw = skb->data;
+ skb->data += ETH_HLEN;
+ }
+
copy_to_user((void *)rx->addr, skb->mac.raw, rx->size);
copy_to_user(net_ring->rx_ring+i, rx, sizeof(rx));
+
+ if (skb->skb_type == SKB_ZERO_COPY)
+ {
+ unmap_domain_mem(skb->head);
+ skb->head = skb->data = skb->tail = (void *)0xdeadbeef;
+ }
}
net_ring->rx_cons = (i+1) & (RX_RING_SIZE-1);
if ( net_ring->rx_cons == net_ring->rx_event )
struct ethhdr *eth;
unsigned char *rawp;
- skb->mac.raw=skb->data;
- skb_pull(skb,dev->hard_header_len);
- eth= skb->mac.ethernet;
+ if (skb->skb_type == SKB_ZERO_COPY)
+ {
+ skb_pull(skb,dev->hard_header_len);
+ skb->mac.raw= (void *)0xdeadbeef;
+ return htons(ETH_P_802_2);
+
+ } else { // SKB_NORMAL
+
+ skb->mac.raw=skb->data;
+ skb_pull(skb,dev->hard_header_len);
+ eth= skb->mac.ethernet;
- if(*eth->h_dest&1)
- {
- if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)
+ if(*eth->h_dest&1)
+ {
+ if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)
skb->pkt_type=PACKET_BROADCAST;
else
skb->pkt_type=PACKET_MULTICAST;
- }
+ }
- /*
- * This ALLMULTI check should be redundant by 1.4
- * so don't forget to remove it.
- *
- * Seems, you forgot to remove it. All silly devices
- * seems to set IFF_PROMISC.
- */
+ /*
+ * This ALLMULTI check should be redundant by 1.4
+ * so don't forget to remove it.
+ *
+ * Seems, you forgot to remove it. All silly devices
+ * seems to set IFF_PROMISC.
+ */
- else if(1 /*dev->flags&IFF_PROMISC*/)
- {
+ else if(1 /*dev->flags&IFF_PROMISC*/)
+ {
if(memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN))
skb->pkt_type=PACKET_OTHERHOST;
- }
+ }
- if (ntohs(eth->h_proto) >= 1536)
+ if (ntohs(eth->h_proto) >= 1536)
return eth->h_proto;
- rawp = skb->data;
+ rawp = skb->data;
- /*
- * This is a magic hack to spot IPX packets. Older Novell breaks
- * the protocol design and runs IPX over 802.3 without an 802.2 LLC
- * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
- * won't work for fault tolerant netware but does for the rest.
- */
- if (*(unsigned short *)rawp == 0xFFFF)
+ /*
+ * This is a magic hack to spot IPX packets. Older Novell breaks
+ * the protocol design and runs IPX over 802.3 without an 802.2 LLC
+ * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
+ * won't work for fault tolerant netware but does for the rest.
+ */
+ if (*(unsigned short *)rawp == 0xFFFF)
return htons(ETH_P_802_3);
- /*
- * Real 802.2 LLC
- */
- return htons(ETH_P_802_2);
+ /*
+ * Real 802.2 LLC
+ */
+ return htons(ETH_P_802_2);
+ }
}
+
int eth_header_parse(struct sk_buff *skb, unsigned char *haddr)
{
struct ethhdr *eth = skb->mac.ethernet;
kmem_cache_free(skbuff_head_cache, skb);
}
+static inline u8 *alloc_skb_data_page(struct sk_buff *skb)
+{
+ struct list_head *list_ptr;
+ struct pfn_info *pf;
+ unsigned long flags;
+
+ spin_lock_irqsave(&free_list_lock, flags);
+
+ if (!free_pfns) return NULL;
+
+ list_ptr = free_list.next;
+ pf = list_entry(list_ptr, struct pfn_info, list);
+ pf->flags = 0; // owned by dom0
+ list_del(&pf->list);
+ pf->next = pf->prev = (pf - frame_table);
+ free_pfns--;
+
+ spin_unlock_irqrestore(&free_list_lock, flags);
+
+ skb->pf = pf;
+ return (u8 *)((pf - frame_table) << PAGE_SHIFT);
+}
+
+static inline void dealloc_skb_data_page(struct sk_buff *skb)
+{
+ struct pfn_info *pf;
+ unsigned long flags;
+
+ pf = skb->pf;
+
+ spin_lock_irqsave(&free_list_lock, flags);
+
+ list_add_tail(&pf->list, &free_list);
+ free_pfns++;
+
+ spin_unlock_irqrestore(&free_list_lock, flags);
+}
+
+struct sk_buff *alloc_zc_skb(unsigned int size,int gfp_mask)
+{
+ struct sk_buff *skb;
+ u8 *data;
+
+ if (in_interrupt() && (gfp_mask & __GFP_WAIT)) {
+ static int count = 0;
+ if (++count < 5) {
+ printk(KERN_ERR "alloc_skb called nonatomically "
+ "from interrupt %p\n", NET_CALLER(size));
+ BUG();
+ }
+ gfp_mask &= ~__GFP_WAIT;
+ }
+
+ /* Get the HEAD */
+ skb = skb_head_from_pool();
+ if (skb == NULL) {
+ skb = kmem_cache_alloc(skbuff_head_cache, gfp_mask & ~__GFP_DMA);
+ if (skb == NULL)
+ goto nohead;
+ }
+
+ /* Get the DATA. Size must match skb_add_mtu(). */
+ size = SKB_DATA_ALIGN(size);
+ data = alloc_skb_data_page(skb);
+ if (data == NULL)
+ goto nodata;
+
+ /* XXX: does not include slab overhead */
+ skb->truesize = size + sizeof(struct sk_buff);
+
+ /* Load the data pointers. */
+ skb->head = data;
+ skb->data = data;
+ skb->tail = data;
+ skb->end = data + size;
+
+ /* Set up other state */
+ skb->len = 0;
+ skb->cloned = 0;
+ skb->data_len = 0;
+ skb->src_vif = VIF_UNKNOWN_INTERFACE;
+ skb->dst_vif = VIF_UNKNOWN_INTERFACE;
+ skb->skb_type = SKB_ZERO_COPY;
+
+ atomic_set(&skb->users, 1);
+ atomic_set(&(skb_shinfo(skb)->dataref), 1);
+ skb_shinfo(skb)->nr_frags = 0;
+ skb_shinfo(skb)->frag_list = NULL;
+ return skb;
+
+nodata:
+ skb_head_to_pool(skb);
+nohead:
+ return NULL;
+}
+
/* Allocate a new skbuff. We do this ourselves so we can fill in a few
* 'private' fields and also do memory statistics to find all the
skb->data_len = 0;
skb->src_vif = VIF_UNKNOWN_INTERFACE;
skb->dst_vif = VIF_UNKNOWN_INTERFACE;
+ skb->skb_type = SKB_NORMAL;
atomic_set(&skb->users, 1);
atomic_set(&(skb_shinfo(skb)->dataref), 1);
if (skb_shinfo(skb)->frag_list)
skb_drop_fraglist(skb);
- kfree(skb->head);
+ if (skb->skb_type == SKB_NORMAL) {
+ kfree(skb->head);
+ } else if (skb->skb_type == SKB_ZERO_COPY) {
+ dealloc_skb_data_page(skb);
+ } else {
+ printk("skb_release_data called with unknown skb type!\n");
+ }
}
}